/**
 * 
 */
package wpmp.security.mgr.service;

import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import wcommons.lang.DateUtils;
import wcommons.lang.NumberUtils;
import wcommons.lang.quickbean.Message;
import wpmp.extjs3.data.Page;
import wpmp.security.mgr.base.BaseService;
import wpmp.security.mgr.base.SqlOrder;
import wpmp.security.mgr.base.SqlUtils;
import wpmp.security.mgr.dao.UserDao;
import wpmp.security.mgr.entity.User;
import wpmp.security.mgr.utils.PageUtils;

/**
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 5:20:06 PM Mar 15, 2013
 */
@Component
@Transactional(rollbackFor = Exception.class)
public class UserService extends BaseService {

	private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

	// 需要更新的字段
	private static final String[] UPDATE_PROPERTIES = { "userName", "loginName", "gender", "orgId", "mobile", "tel",
			"email", "address", "memo", "isAdmin" };

	private UserDao dao;

	private static final String SQL_SELECT_SIMPLE = "SELECT id,login_name,user_name,EXISTS(SELECT 1 from sys_user_role_rela WHERE role_id=? AND user_id=thiz.id) has_role FROM sys_user thiz WHERE 1=1 ";
	private static final String SQL_COUNT_SIMPLE = "SELECT COUNT(1) total FROM sys_user thiz WHERE 1=1 ";

	@Autowired
	public void setDao(UserDao dao) {
		this.dao = dao;
	}

	public User get(Long id) {
		User entity = dao.get(id);
		if (entity == null) {
			return entity;
		}
		User result = new User();
		BeanUtils.copyProperties(entity, result);
		return result;
	}

	private Criteria getCriteria(User entity) {
		Criteria criteria = dao.createCriteria();
		if (StringUtils.isNotBlank(entity.getUserName())) {
			criteria.add(Restrictions.like("userName", entity.getUserName(), MatchMode.ANYWHERE));
		}
		if (StringUtils.isNotBlank(entity.getKw())) {
			Disjunction c = Restrictions.disjunction();
			c.add(Restrictions.like("userName", entity.getKw(), MatchMode.ANYWHERE));
			c.add(Restrictions.like("loginName", entity.getKw(), MatchMode.ANYWHERE));
			criteria.add(c);
		}
		return criteria;
	}

	public List<User> list(User entity, Page page) {
		return dao.queryForList(PageUtils.setCriteria(getCriteria(entity), page, Order.asc("loginName")));
	}

	public int count(User entity) {
		return dao.queryForInt(getCriteria(entity));
	}

	public Message validateLoginName(User entity) {
		Criteria criteria = dao.createCriteria(Restrictions.eq("loginName", entity.getLoginName()));
		if (NumberUtils.gtZero(entity.getId())) {
			criteria.add(Restrictions.ne("id", entity.getId()));
		}
		if (dao.queryForInt(criteria) > 0) {
			return Message.getErrorMessage("登录名[" + entity.getLoginName() + "]已存在");
		}
		return Message.getDefaultMessage();
	}

	public Message insert(User entity) {
		final Message message = validateLoginName(entity);
		if (message.notpass()) {
			return message;
		}

		final Timestamp currentTime = new Timestamp(System.currentTimeMillis());
		// 默认密码：123456
		entity.setPassword(DigestUtils.md5Hex("123456"));
		entity.setCreateTime(currentTime);
		entity.setCreateUser(entity.getSysLoginName());
		entity.setUpdateTime(currentTime);
		entity.setUpdateUser(entity.getSysLoginName());
		dao.save(entity);

		return message;
	}

	public Message update(User entity) throws Exception {
		final Message message = validateLoginName(entity);
		if (message.notpass()) {
			return message;
		}

		final User result = dao.get(entity.getId());

		wcommons.beanutils.BeanUtils.copyProperties(result, entity, UPDATE_PROPERTIES, false);

		result.setUpdateTime(DateUtils.newTimestamp());
		result.setUpdateUser(entity.getSysLoginName());
		dao.save(result);

		return message;
	}

	/**
	 * 给用户授权角色
	 * 
	 * <pre>
	 * 在原有的基础上添加角色
	 * </pre>
	 * @param userIds
	 * @param roleIds
	 * @return
	 */
	public Message addRole(Long[] userIds, Long[] roleIds) {
		if (ArrayUtils.isEmpty(userIds)) {
			return Message.getErrorMessage("请选择用户");
		}
		if (ArrayUtils.isEmpty(roleIds)) {
			return Message.getErrorMessage("请选择角色");
		}

		int[] status = dao.insertUserRoleRelaWhereNotExists(userIds, roleIds);

		if (LOG.isDebugEnabled()) {
			LOG.debug("INSERT UserRoleRela: userIds[{}], roleIds[{}], return [{}]", ArrayUtils.toString(userIds),
					ArrayUtils.toString(roleIds), ArrayUtils.toString(status));
		}

		return Message.getDefaultMessage();
	}

	/**
	 * 取消用户的授权角色
	 * @param userIds
	 * @param roleIds
	 * @return
	 */
	public Message removeRole(Long[] userIds, Long[] roleIds) {
		if (ArrayUtils.isEmpty(userIds)) {
			return Message.getErrorMessage("请选择用户");
		}
		if (ArrayUtils.isEmpty(roleIds)) {
			return Message.getErrorMessage("请选择角色");
		}
		int[] status = dao.deleteUserRoleRela(userIds, roleIds);

		if (LOG.isDebugEnabled()) {
			LOG.debug("DELETE UserRoleRela: userIds[{}], roleIds[{}], return [{}]", ArrayUtils.toString(userIds),
					ArrayUtils.toString(roleIds), ArrayUtils.toString(status));
		}

		return Message.getDefaultMessage();
	}

	/**
	 * 给用户重新授权角色
	 * @param userId
	 * @param roleIds
	 * @return
	 */
	public Message resetRole(Long userId, Long[] roleIds) {
		if (!NumberUtils.gtZero(userId)) {
			return Message.getErrorMessage("请选择用户");
		}
		if (ArrayUtils.isEmpty(roleIds)) {
			return Message.getErrorMessage("请选择角色");
		}
		// 先删除用户所有权限
		int st = dao.deleteUserRoleRela(userId);

		if (LOG.isDebugEnabled()) {
			LOG.debug("DELETE UserRoleRela: userIds[{}], return [{}]", userId, st);
		}

		int[] status = dao.insertUserRoleRela(userId, roleIds);

		if (LOG.isDebugEnabled()) {
			LOG.debug("INSERT UserRoleRela: userIds[{}], roleIds[{}], return [{}]", userId,
					ArrayUtils.toString(roleIds), ArrayUtils.toString(status));
		}

		return Message.getDefaultMessage();
	}

	/**
	 * 重置密码
	 * @param id
	 * @return
	 */
	public Message resetPassword(User entity) {
		User result = dao.get(entity.getId());
		result.setPassword("BtkuvuJhZBY=");
		result.setUpdateTime(DateUtils.newTimestamp());
		result.setUpdateUser(entity.getSysLoginName());
		dao.save(result);

		return Message.getNoteMessage("密码已被重置成123456，为了保证帐号安全，请尽快修改密码！");
	}

	/**
	 * 删除用户
	 * @param entity
	 * @return
	 */
	public Message delete(User entity) {
		if (ArrayUtils.isEmpty(entity.getIds())) {
			return Message.getErrorMessage("请选择用户");
		}
		List<User> entities = new LinkedList<User>();
		for (Long id : entity.getIds()) {
			User e = dao.get(id);
			if (e == null) {
				continue;
			}
			entities.add(e);
		}
		Message message = Message.getDefaultMessage();
		if (!entities.isEmpty()) {
			dao.delete(entities);
		}

		// 删除与角色的关系
		dao.deleteUserRoleRela(entity.getIds());
		return message;
	}

	private void setSqlCondition(User entity, StringBuilder sql, List<Object> params) {
		if (StringUtils.isNotBlank(entity.getUserName())) {
			sql.append(" AND thiz.user_name LIKE CONCAT('%',?,'%') ");
			params.add(entity.getUserName());
		}
		if (entity.getHasRole() != null) {
			sql.append(" AND ").append(entity.getHasRole() ? "EXISTS" : "NOT EXISTS");
			sql.append(" (SELECT 1 FROM sys_user_role_rela WHERE user_id=thiz.id AND role_id=?) ");
			params.add(entity.getRoleId());
		}
	}

	private void setSqlOrder(StringBuilder sql, Page page, SqlOrder... sqlOrders) {
		String orderBySql;
		if (StringUtils.isBlank(page.getSort()) || StringUtils.isBlank(page.getDir())) {
			orderBySql = SqlUtils.getOrderBySql(sqlOrders);
		}
		else {
			orderBySql = SqlUtils.getOrderBySql(page.getSort(), page.getDir());
		}
		if (StringUtils.isNotBlank(orderBySql)) {
			sql.append(" ORDER BY ").append(orderBySql);
		}
		sql.append(" LIMIT ").append(page.getStart()).append(",").append(page.getLimit());
	}

	/**
	 * 获取授权用户的基本信息
	 * @param entity
	 * @param page
	 * @return [{id:xx,userName:xx,mobile,xx,tel:xx,hasAuth:xx}, ...]
	 */
	public List<User> listAuth(User entity, Page page) {
		StringBuilder sql = new StringBuilder(SQL_SELECT_SIMPLE);
		List<Object> params = new LinkedList<Object>();
		params.add(entity.getRoleId());

		setSqlCondition(entity, sql, params);

		setSqlOrder(sql, page, SqlOrder.asc("user_name"));

		if (LOG.isDebugEnabled()) {
			LOG.debug(sql.toString());
		}

		List<User> results = new LinkedList<User>();

		SqlRowSet rs = dao.getJdbcTemplate().queryForRowSet(sql.toString(), params.toArray());
		while (rs.next()) {
			User result = new User();
			wcommons.beanutils.BeanUtils.copySqlRowSetToBean(result, rs);
			results.add(result);
		}

		return results;
	}

	/**
	 * 获取授权用户的数量
	 * @param entity
	 * @return
	 */
	public int countAuth(User entity) {
		final StringBuilder sql = new StringBuilder(SQL_COUNT_SIMPLE);
		final List<Object> params = new LinkedList<Object>();

		setSqlCondition(entity, sql, params);

		if (LOG.isDebugEnabled()) {
			LOG.debug(sql.toString());
		}

		final SqlRowSet rs = dao.getJdbcTemplate().queryForRowSet(sql.toString(), params.toArray());
		return rs.next() ? rs.getInt("total") : 0;
	}
}
